﻿using System;
using FunctionalCLR.Core;
using FunctionalCLR.Shell;
using NUnit.Framework;
using FunctionalCLR.Shell.Optimization;

namespace Zove.Test
{
    [TestFixture]
    public class FunctionalCLRTests : AbstractTests
    {
        [Test]
        public void TestDynamicFunctionLoader()
        {
            IFunctionManager funMgr = new MockFunctionManager();
            DefaultFunctionLoader loader
                = new DefaultFunctionLoader(funMgr);

            loader.Load(Utils.FunctionPath);
        }

        [Test]
        public void TestLoadFromAssembly()
        {
            DefaultFunctionLoader loader
                = new DefaultFunctionLoader(
                    new MockFunctionManager());

            loader.Load(Utils.FunctionPath);
        }
        
        [Test]
        public void TestIf()
        {
            IContext cnt = Execute(@"a=1;
if(a<2,a=3,a=5);
echo(a);");

            double var = Convert.ToDouble(
                cnt.GetVariable("a"));
            Assert.AreEqual(3, var);
        }

        [Test]
        public void TestBlock()
        {
            IContext cnt = Execute(@"{a=1};echo(a);");

            double var = Convert.ToDouble(
                cnt.GetVariable("a"));
            Assert.AreEqual(1, var);
        }

        [Test]
        public void TestRec()
        {
            IContext cnt = this.Execute(@"r(x):=if(x>0,x+r(x-1),0);
a=r(2);
echo(a);");
            double var = (double)cnt.GetVariable("a");
            Assert.AreEqual(3, var);
        }

        [Test]
        public void TestFact()
        {
            IContext cnt = this.Execute(@"fact(x):=if(x<=0,0,if(x==1,1,x*fact(x-1)));
m=fact(5);
echo(m);");
            double var = (double)cnt.GetVariable("m");
            Assert.AreEqual(6, var);
        }

        [Test]
        public void TestPick()
        {
            IContext cnt = this.Execute(@"a=pick({1,2,3},2);a=a+1;echo(a);");

            double var = (double)cnt.GetVariable("a");
            Assert.AreEqual(3, var);
        }

        [Test]
        public void TestAssign()
        {
            IContext context = this.Execute("x=3;");

            object v = context.GetVariable("x");
            double var = Convert.ToDouble(v);
            Assert.AreEqual(3, var);
        }

        [Test]
        public void TestWhile()
        {
            IContext cnt = this.Execute(@"
                a=1;
                while(
                    a<56,
                    a=a+1);
                echo(a);");

            double var = Convert.ToDouble(
                cnt.GetVariable("a"));
            Assert.AreEqual(5, var);
        }

        [Test]
        public void TestFor()
        {
            IContext cnt = this.Execute(@"a=1;b=1;for(a=1,a<7,a=a+1,b=b*2);echo(a);echo(b);");

            double var = Convert.ToDouble(
                cnt.GetVariable("a"));
            Assert.AreEqual(6, var);
        }

        [Test]
        public void TestBreak()
        {
            IContext cnt = this.Execute("a=1;while(a<3, {a=a+1,break()});echo(a);");

            double var = Convert.ToDouble(
                cnt.GetVariable("a"));
            Assert.AreEqual(3, var);
        }

        [Test]
        public void TestTry()
        {
            Execute("a=1;try({a=2,throw(\"hello\"),echo(a)},echo(\"error\")});echo(a);");
        }

        [Test]
        public void TestMain()
        {
            IContext cnt = Execute(@"a=0;main():=a=5;echo(a);");

            double var = Convert.ToDouble(
                cnt.GetVariable("a"));
            Assert.AreEqual(5, var);
        }
    }
}
